﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SimpleData.Infrastructure.JavaScript
{
	public struct JsObject
	{
		private object value;

		//public JsObject()
		//    : this( null )
		//{ }

		public JsObject( object obj )
		{
			this.value = obj;
		}

		public bool IsNumber
		{
			get
			{
				if ( this.value != null )
					return this.value is Number || !Number.NotNumbers.Contains( Convert.GetTypeCode( this.value ) );
				else
					return false;
			}
		}

		public override bool Equals( object obj )
		{
			if ( obj is JsObject )
				return this.value.Equals( ( ( JsObject )obj ).value );
			else
				return false;
		}

		public override int GetHashCode()
		{
			if ( this.value == null )
				return 0;
			else
				return this.value.GetHashCode();
		}

		public override string ToString()
		{
			if ( this.value == null )
				return String.Empty;
			else
				return this.value.ToString();
		}

		public static implicit operator JsObject( int i )
		{
			return new JsObject( i );
		}

		public static implicit operator JsObject( double d )
		{
			return new JsObject( d );
		}

		public static implicit operator JsObject( long l )
		{
			return new JsObject( l );
		}

		public static implicit operator JsObject( string s )
		{
			return new JsObject( s );
		}

		public static explicit operator Number( JsObject o )
		{
			if ( o.value == null )
				return Number.Null;
			else
				return ( double )o.value;
		}

		public static explicit operator Text( JsObject o )
		{
			return ( string )o.value;
		}

		public static Number operator +( JsObject o, Number n )
		{
			if ( o.value == null )
				return n;
			else if ( o.IsNumber )
				return ( Convert.ToDouble( o.value ) ) + n;
			else
				throw new InvalidCastException( String.Format( "Não é possível converter {0} para um valor numérico.", o.ToString() ) );
		}

		public static Number operator +( Number n, JsObject o )
		{
			return o + n;
		}

		public static Text operator +( JsObject o, Text t )
		{
			return String.Concat( o.ToString(), t.ToString() );
		}

		public static Text operator +( Text t, JsObject o )
		{
			return String.Concat( t.ToString(), o.ToString() );
		}

		public static implicit operator JsObject( Number o )
		{
			if ( o.value.HasValue )
				return new JsObject( o.value.Value );
			else
				return new JsObject( null );
		}

		public static implicit operator JsObject( Text t )
		{
			return new JsObject( t.value );
		}

		public static bool operator true( JsObject o )
		{
			if ( o.value != null )
			{
				if ( o.value is Number )
					return ( ( Number )o.value ) ? true : false;
				else if ( o.value is Text )
					return ( ( Text )o.value ) ? true : false;
				else
					return true;
			}

			return false;
		}

		public static bool operator false( JsObject o )
		{
			if ( o.value == null )
				return false;
			else
			{
				if ( o.value is Number )
					return ( ( Number )o.value ) ? true : false;
				else if ( o.value is Text )
					return ( ( Text )o.value ) ? true : false;
				else
					return false;
			}
		}

		public static bool operator ==( JsObject x, JsObject y )
		{
			return x.value == y.value;
		}

		public static bool operator !=( JsObject x, JsObject y )
		{
			return x.value != y.value;
		}

		public static bool operator !( JsObject o )
		{
			return o == null;
		}
	}
}
